package com.tomtop.core.web.config;

import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ThreadFactory;

import org.apache.http.Header;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.MimeTypeUtils;

@Configuration
@ConditionalOnMissingBean(ClientHttpRequestFactory.class)
@ConditionalOnClass(PoolingHttpClientConnectionManager.class)
public class HttpComponentsConfig {

	final static Logger LOGGER = LoggerFactory.getLogger(HttpComponentsConfig.class);

	@Bean
	@ConditionalOnMissingBean(ThreadFactory.class)
	ThreadFactory threadFactory() {
		return new ThreadPoolTaskExecutor();
	}

	@Bean
	@ConditionalOnMissingBean
	RequestConfig.Builder requestConfig() {
		return RequestConfig.custom().setConnectionRequestTimeout(8000).setConnectTimeout(300000)
				.setSocketTimeout(300000).setMaxRedirects(1000).setRedirectsEnabled(true);
	}

	@Bean
	@ConditionalOnMissingBean
	SocketConfig.Builder socketConfig() {
		return SocketConfig.custom().setSoTimeout(60000).setSoKeepAlive(true);
	}

	@Bean
	@ConditionalOnMissingBean
	HttpRequestRetryHandler requestRetryHandler() {
		return new DefaultHttpRequestRetryHandler(3, true);
	}

	@Bean
	@ConditionalOnMissingBean
	Collection<? extends Header> defaultHeaders() {
		return Collections.singletonList(new BasicHeader("Content-Type", MimeTypeUtils.APPLICATION_JSON_VALUE));
	}

	@Bean
	@ConditionalOnMissingBean
	String userAgent(@Value("${spring.application.name:Other}") String app) {
		return "laolei HttpClient( " + app + ")";
	}

	@Bean
	@ConditionalOnMissingBean
	RegistryBuilder<ConnectionSocketFactory> registryConnectionSocketFactory() {
		return RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory())
				.register("https", SSLConnectionSocketFactory.getSystemSocketFactory());
	}

	@Bean(destroyMethod = "close")
	PoolingHttpClientConnectionManager syncConnectionPoolManager(
			RegistryBuilder<ConnectionSocketFactory> registryBuilder, SocketConfig.Builder socketConfig) {
		PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager(registryBuilder.build());
		poolConnManager.setDefaultSocketConfig(socketConfig.build());
		poolConnManager.setMaxTotal(150);
		poolConnManager.setDefaultMaxPerRoute(10);
		poolConnManager.setValidateAfterInactivity(1900);
		return poolConnManager;
	}

	@Scheduled(fixedDelay = 6 * 60 * 1000, initialDelay = 1000)
	void showHttpConnectionPoolState() {
		LOGGER.debug("当前http连接池状态 {}", syncConnectionPoolManager(null, null).getTotalStats());
	}

	@Bean
	HttpClientBuilder httpClient(HttpRequestRetryHandler requestRetryHandler, RequestConfig.Builder requestConfig,
			HttpClientConnectionManager syncConnectionPoolManager, Collection<? extends Header> defaultHeaders,
			String userAgent) {
		HttpClientBuilder clientBuilder = HttpClients.custom()
				.setConnectionManager(syncConnectionPoolManager)
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
				.setConnectionManagerShared(true)
				.setDefaultRequestConfig(requestConfig.build())
				.setDefaultHeaders(defaultHeaders)
				.setRetryHandler(requestRetryHandler)
				.setUserAgent(userAgent);
		return clientBuilder;
	}

	@Bean
	ClientHttpRequestFactory clientHttpRequestFactory(HttpClientBuilder httpClient) {
		return new HttpComponentsClientHttpRequestFactory(httpClient.build());
	}
}
